package com.atguigu.gmall.product.service.impl;

import com.atguigu.gmall.model.product.*;
import com.atguigu.gmall.product.mapper.*;
import com.atguigu.gmall.product.service.ItemService;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.log4j.Log4j2;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

/**
 * 给Item-Item调用的内部调用接口实现类
 */
@Log4j2
@Service
public class ItemServiceImpl implements ItemService {
    @Resource
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;

    @Resource
    private SkuInfoMapper skuInfoMapper;

    /**
     * 显示商品详情
     *
     * @param skuId
     * @return
     */
    @Override
    public SkuInfo getSkuInfo(Long skuId) {
        //查询redis中是否有数据
        SkuInfo skuInfo =
                (SkuInfo)redisTemplate.opsForValue().get("sku:" + skuId + ":info");
        //若redis中有数据直接返回
        if (skuInfo != null ){
            return skuInfo;
        }
        //若没有查询数据库 并将结果存入redis
        RLock lock = redissonClient.getLock("sku：" + skuId + "：lock");
        try {
            lock.tryLock(10,10, TimeUnit.SECONDS);
            log.info("获取锁成功");
            try {
                 skuInfo = skuInfoMapper.selectById(skuId);
                 if (skuInfo == null ||skuInfo.getId() == null){
                     //为了防止缓存击穿，设置一个假数据
                     skuInfo = new SkuInfo();
                     //假数据过期时间为5分钟，以便于对应Id 新增了真实的数据
                     redisTemplate.opsForValue().set("sku:"+skuId+":info", skuInfo,60*5,TimeUnit.SECONDS);
                 }else {
                     //查询导数据将数据保存一天
                     redisTemplate.opsForValue().set("sku:"+skuId+":info", skuInfo,24*60*60,TimeUnit.SECONDS);
                 }
                 return skuInfo;
            }catch (Exception e){
                e.printStackTrace();
                log.error("加锁成功，处理数据时异常，当前商品Id为："+skuId);
            }finally {
                //释放锁
                lock.unlock();
            }
        }catch (Exception e){
            e.printStackTrace();
            log.error("获取锁失败，商品Id为："+skuId);
        }
        return null;
    }
    @Resource
    private SkuImageMapper skuImageMapper;
    /**
     * 查询商品图片集合
     *
     * @param skuId
     * @return
     */
    @Override
    public List<SkuImage> getSkuImage(Long skuId) {
        return skuImageMapper.selectList(new LambdaQueryWrapper<SkuImage>().eq(SkuImage::getSkuId,skuId));
    }

    /**
     * 查询商品价格
     *
     * @param skuId
     * @return
     */
    @Override
    public BigDecimal getPrice(Long skuId) {
        return skuInfoMapper.selectById(skuId).getPrice();
    }

    @Resource
    private BaseCategoryViewMapper baseCategoryViewMapper;
    /**
     * 根据三级分类Id 查询三级分类
     *
     * @param category3Id
     * @return
     */
    @Override
    public BaseCategoryView getCategory(Long category3Id) {
        return baseCategoryViewMapper.selectById(category3Id);
    }

    @Resource
    private SpuSaleAttrMapper spuSaleAttrMapper;
    /**
     * 查询商品销售属性
     *
     * @param skuId
     * @param spuId
     * @return
     */
    @Override
    public List<SpuSaleAttr> getSpuSaleAttr(Long skuId, Long spuId) {
        return spuSaleAttrMapper.getSpuSaleAttrBySpuIdAndSkuId(skuId,spuId);
    }

    @Resource
    private SkuSaleAttrValueMapper skuSaleAttrValueMapper;
    /**
     * 通过spuId查询商品的skuInfo值
     *
     * @param spuId
     * @return
     */
    @Override
    public Map getSkuValuesBySpu(Long spuId) {
        Map map = new ConcurrentHashMap();
        List<Map> skuSaleLAttrList = skuSaleAttrValueMapper.getSkuSaleLAttrList(spuId);
        skuSaleLAttrList.stream().forEach(skuSaleMap->{
            Object skuId = skuSaleMap.get("sku_id");
            Object skuSaleId = skuSaleMap.get("sku_sale_id");
            map.put(skuSaleId,skuId);

        });
        return map;
    }

    @Resource
    private BaseTrademarkMapper baseTrademarkMapper;
    /**
     * 查询品牌信息
     *
     * @param id
     */
    @Override
    public BaseTrademark getTrademark(Long id) {
        return baseTrademarkMapper.selectById(id);
    }

    @Resource
    private BaseAttrInfoMapper baseAttrInfoMapper;
    /**
     * 查询平台属性
     *
     * @param skuId
     * @return
     */
    @Override
    public List<BaseAttrInfo> getSkuAttrValue(Long skuId) {
        return baseAttrInfoMapper.getSkuAttrValue(skuId);
    }

    /**
     * 扣减商品库存
     *
     * @param detailMap
     */
    @Override
    public void deductSku(Map<String, String> detailMap) {
        detailMap.entrySet().stream().forEach(map->{
            //获取要扣减的商品ID
            String skuId = map.getKey();
            //获取要扣减的商品数量
            String skuNum = map.getValue();
            //利用sql语句一步完成查询 判断和修改的操作 没有时间差，不会出现超卖，且使用了乐观锁机制可以保证安全，
            int i = skuInfoMapper.
                    deductSku(Long.parseLong(skuId), Integer.parseInt(skuNum));
            if (i <= 0){
                throw new RuntimeException("商品扣减失败！！");
            }
            //下面的方法存在时间差可能会出现超卖的情况
           /* //先查询商品是否存在
            SkuInfo skuInfo = skuInfoMapper.selectById(skuId);
            if (skuInfo == null || skuInfo.getId() == null){
                throw new RuntimeException("商品不存在，扣减商品数量失败！！");
            }
             Integer num = Integer.parseInt(skuNum);
            Integer stock = skuInfo.getStock()-num;
            if (stock < 0){
                throw new RuntimeException("商品扣减失败，商品数量不足！！");
            }else {
                skuInfo.setStock(stock);
                int update =
                        skuInfoMapper.update(skuInfo,
                                new LambdaQueryWrapper<SkuInfo>()
                                        .eq(BaseEntity::getId, skuId));
            }*/
        });
    }

    /**
     * 回滚库存
     *
     * @param rollbackMap
     */
    @Override
    public void rollBackStock(Map<String, String> rollbackMap) {
        if (rollbackMap == null){
            return;
        }
        rollbackMap.entrySet().stream().forEach(map->{
            String skuId = map.getKey();
            String skuNum = map.getValue();
            //使用SQL直接一步完成
            int update = skuInfoMapper.rollBackStock(Long.parseLong(skuId), Integer.parseInt(skuNum));
            if (update < 0){
                throw new RuntimeException("回滚库存失败");
            }
        });
    }
}
